import {
  onBeforeUnmount,
  ref,
  shallowRef,
  onMounted,
  watch,
  Ref,
  defineComponent,
} from 'vue';
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import { IEditorConfig, IToolbarConfig } from '@wangeditor/editor';
import type { IDomEditor } from '@wangeditor/editor';
import { getCookie } from 'qx-util';
import {
  getEditorEmits,
  getHtmlProps,
  useNamespace,
} from '@ibiz-template/vue3-util';
import { CoreConst } from '@ibiz-template/core';
import { HtmlEditorController } from '../html-editor.controller';
import './wang-editor.scss';

type InsertFnType = (_url: string, _alt: string, _href: string) => void;

const IBizHtml = defineComponent({
  name: 'IBizHtml',
  props: getHtmlProps<HtmlEditorController>(),
  emits: getEditorEmits(),
  setup(props, { emit }) {
    const ns = useNamespace('html');

    const c = props.controller!;

    // 编辑器实例，必须用 shallowRef，重要！
    const editorRef = shallowRef();

    // 内容 HTML
    const valueHtml = ref('');

    // 请求头
    const headers: Ref<IData> = ref({
      Authorization: `Bearer ${getCookie(CoreConst.TOKEN)}`,
    });

    // 上传文件路径
    const uploadUrl: Ref<string> = ref('');

    // 下载文件路径
    const downloadUrl: Ref<string> = ref('');

    // data响应式变更基础路径
    watch(
      () => props.data,
      newVal => {
        if (newVal) {
          const urls = c.calcBaseUrl(newVal);
          uploadUrl.value = urls.uploadUrl;
          downloadUrl.value = urls.downloadUrl;
        }
      },
      { immediate: true, deep: true },
    );

    // 自定义校验链接
    const customCheckLinkFn = (
      text: string,
      url: string,
    ): string | boolean | undefined => {
      if (!url) {
        return;
      }
      // if (url.indexOf('http') !== 0) {
      //   return '链接必须以 http/https 开头';
      // }
      return true;

      // 返回值有三种选择：
      // 1. 返回 true ，说明检查通过，编辑器将正常插入链接
      // 2. 返回一个字符串，说明检查未通过，编辑器会阻止插入。会 alert 出错误信息（即返回的字符串）
      // 3. 返回 undefined（即没有任何返回），说明检查未通过，编辑器会阻止插入。但不会提示任何信息
    };

    // 自定义转换链接 url
    const customParseLinkUrl = (url: string): string => {
      // if (url.indexOf('http') !== 0) {
      //   return `http://${url}`;
      // }
      return url;
    };

    // 工具栏配置
    const toolbarConfig: Partial<IToolbarConfig> = {
      excludeKeys: ['group-video'],
    };

    // 编辑器配置
    const editorConfig: Partial<IEditorConfig> = {
      placeholder: c.placeHolder,
      readOnly: props.readonly,
      MENU_CONF: {
        // 图片上传
        uploadImage: {
          // 上传地址
          server: uploadUrl.value,

          // form-data fieldName ，默认值 'wangeditor-uploaded-image'
          fieldName: 'file',

          // 单个文件的最大体积限制，默认为 2M
          maxFileSize: 10 * 1024 * 1024, // 10M

          // 最多可上传几个文件，默认为 100
          maxNumberOfFiles: 10,

          // 选择文件时的类型限制，默认为 ['image/*'] 。如不想限制，则设置为 []
          allowedFileTypes: [],

          // 自定义增加 http  header
          headers: headers.value,

          // 跨域是否传递 cookie ，默认为 false
          withCredentials: true,

          // 上传之前触发
          onBeforeUpload(file: File) {
            // TS 语法
            // onBeforeUpload(file) {    // JS 语法
            // file 选中的文件，格式如 { key: file }
            return file;

            // 可以 return
            // 1. return file 或者 new 一个 file ，接下来将上传
            // 2. return false ，不上传这个 file
          },

          // 上传进度的回调函数
          onProgress(progress: number) {
            console.log('progress', progress);
          },

          // 单个文件上传成功之后
          onSuccess(file: File, res: IData) {
            console.log(`${file.name} 上传成功`, res);
          },

          // 单个文件上传失败
          onFailed(file: File, res: IData) {
            console.log(`${file.name} 上传失败`, res);
          },

          // 上传错误，或者触发 timeout 超时
          onError(file: File, err: IData, res: IData) {
            console.log(`${file.name} 上传出错`, err, res);
          },

          // 自定义插入图片
          async customInsert(res: IData, insertFn: InsertFnType) {
            const url = downloadUrl.value.replace('%fileId%', res.id);
            const alt = res.filename;
            // 从 res 中找到 url alt href ，然后插入图片
            insertFn(url, alt, '');
          },
        },
        // 插入链接
        insertLink: {
          checkLink: customCheckLinkFn, // 也支持 async 函数
          parseLinkUrl: customParseLinkUrl, // 也支持 async 函数
        },
        // 更新链接
        editLink: {
          checkLink: customCheckLinkFn, // 也支持 async 函数
          parseLinkUrl: customParseLinkUrl, // 也支持 async 函数
        },
      },
    };

    // 组件销毁时，也及时销毁编辑器，重要！
    onBeforeUnmount(() => {
      const editor = editorRef.value;
      if (editor == null) return;

      editor.destroy();
    });

    // 编辑器回调函数
    // 编辑器创建完毕时的回调函数
    const handleCreated = (editor: IDomEditor) => {
      editorRef.value = editor; // 记录 editor 实例，重要！
      // 配置菜单
      // setTimeout(() => {
      //   const toolbar = DomEditor.getToolbar(editor);
      //   const curToolbarConfig = toolbar?.getConfig();
      //   console.log(curToolbarConfig?.toolbarKeys); // 当前菜单排序和分组
      // }, 3000);
    };
    // 编辑器内容、选区变化时的回调函数
    const handleChange = (editor: IDomEditor) => {
      // console.log('change:', editor.getHtml());
      const html = editor.getHtml();
      // wangEditor初始值抛空字符串给后台
      const emitValue = html === '<p><br></p>' ? '' : html;
      emit('change', emitValue);
    };
    // 编辑器销毁时的回调函数。调用 editor.destroy() 即可销毁编辑器
    const handleDestroyed = (_editor: IDomEditor) => {
      // console.log('destroyed', _editor);
    };
    // 编辑器 focus 时的回调函数
    const handleFocus = (_editor: IDomEditor) => {
      // console.log('focus', _editor);
    };
    // 编辑器 blur 时的回调函数。
    const handleBlur = (_editor: IDomEditor) => {
      // console.log('blur', _editor);
    };
    // 自定义编辑器 alert
    const customAlert = (info: string, type: string) => {
      // eslint-disable-next-line no-alert
      alert(`【自定义提示】${type} - ${info}`);
    };
    // 自定义粘贴。可阻止编辑器的默认粘贴，实现自己的粘贴逻辑
    const customPaste = (
      editor: IDomEditor,
      event: ClipboardEvent,
      callback: (_n: boolean) => void,
    ) => {
      // 返回值（注意，vue 事件的返回值，不能用 return）
      // callback(false); // 返回 false ，阻止默认粘贴行为
      callback(true); // 返回 true ，继续默认的粘贴行为
    };

    // 插入文本
    const insertText = (str: string) => {
      const editor = editorRef.value;
      if (editor == null) return;

      editor.insertText(str);
    };

    // 获取非格式化的 html
    const printHtml = () => {
      const editor = editorRef.value;
      if (editor == null) return;
      console.log(editor.getHtml());
    };

    // 禁用编辑器
    const disable = () => {
      const editor = editorRef.value;
      if (editor == null) return;
      editor.disable();
    };

    // 取消禁用编辑器
    const enable = () => {
      const editor = editorRef.value;
      if (editor == null) return;
      editor.enable();
    };

    onMounted(() => {
      // 监听值变化赋值
      watch(
        () => props.value,
        (newVal, oldVal) => {
          if (
            newVal !== oldVal &&
            (typeof props.value === 'string' || newVal === null)
          ) {
            if (newVal === null) {
              valueHtml.value = '';
            } else {
              valueHtml.value = newVal as string;
            }
          }
        },
        { immediate: true },
      );

      // 监听disabled禁用
      watch(
        () => props.disabled,
        (newVal, oldVal) => {
          if (newVal !== oldVal) {
            if (newVal === true) {
              disable();
            } else {
              enable();
            }
          }
        },
        { immediate: true },
      );
    });

    return {
      ns,
      editorRef,
      mode: 'default',
      valueHtml,
      toolbarConfig,
      editorConfig,
      handleCreated,
      handleChange,
      handleDestroyed,
      handleFocus,
      handleBlur,
      customAlert,
      customPaste,
      insertText,
      printHtml,
      disable,
      enable,
    };
  },
  render() {
    return (
      <div class={this.ns.b()}>
        <div style='border: 1px solid #ccc; margin-top: 10px'>
          <Toolbar
            editor={this.editorRef}
            default-config={this.toolbarConfig}
            mode={this.mode}
            style='border-bottom: 1px solid #ccc'
          />
          <Editor
            v-model={this.valueHtml}
            default-config={this.editorConfig}
            mode={this.mode}
            style='height: 400px; overflow-y: hidden'
            onOnCreated={this.handleCreated}
            onOnChange={this.handleChange}
            onOnDestroyed={this.handleDestroyed}
            onOnFocus={this.handleFocus}
            onOnBlur={this.handleBlur}
            oncustomAlert={this.customAlert}
            oncustomPaste={this.customPaste}
          />
        </div>
      </div>
    );
  },
});

export default IBizHtml;
